#include <stdio.h>
#include "w25q32.h"

// 初始化
void W25Q32_Init(void)
{
    SPI_Init();
}

// 读取ID
void W25Q32_ReadID(uint8_t *mid, uint16_t *did)
{
    SPI_Start();

    // 1. 发送指令 9fh
    SPI_SwapByte(0x9f);

    // 2. 获取制造商ID（为了读取数据，发送什么不重要）
    *mid = SPI_SwapByte(0xff);

    // 3. 获取设备ID
    *did = 0;
    *did |= SPI_SwapByte(0xff) << 8;
    *did |= SPI_SwapByte(0xff) & 0xff;

    SPI_Stop();
}

// 开启写使能
static void W25Q32_WriteEnable(void)
{
    SPI_Start();
    SPI_SwapByte(0x06);
    SPI_Stop();
}

// 关闭写使能
static void W25Q32_WriteDisable(void)
{
    SPI_Start();
    SPI_SwapByte(0x04);
    SPI_Stop();
}

// 等待状态不为忙（busy）
static void W25Q32_WaitNotBusy(void)
{
    SPI_Start();

    // 发送读取状态寄存器指令
    SPI_SwapByte(0x05);

    // 等待收到的数据末位变成0
    while (SPI_SwapByte(0xff) & 0x01)
    {
    }

    SPI_Stop();
}

// 擦除段（sector erase）,地址只需要块号和段号
static void W25Q32_EraseSector(uint8_t block, uint8_t sector)
{
    if(block >= W25Q32_BLOCK_MAX || sector >= W25Q32_SECTOR_MAX) {
        return;
    }

    // 首先等待状态不为忙
    W25Q32_WaitNotBusy();

    // 开启写使能
    W25Q32_WriteEnable();

    // 计算要发送的地址（段首地址）
    uint32_t addr = (block << 16) + (sector << 12);

    SPI_Start();

    // 发送指令
    SPI_SwapByte(0x20);

    SPI_SwapByte(addr >> 16 & 0xff); // 第一个字节
    SPI_SwapByte(addr >> 8 & 0xff);  // 第二个字节
    SPI_SwapByte(addr >> 0 & 0xff);  // 第三个字节

    SPI_Stop();

    W25Q32_WriteDisable();
}

// 写入（页写）
static void W25Q32_PageWrite(uint8_t block, uint8_t sector, uint8_t page, uint8_t *data, uint16_t len)
{
    if(block >= W25Q32_BLOCK_MAX || sector >= W25Q32_SECTOR_MAX || page >= W25Q32_PAGE_MAX) {
        return;
    }

    if(NULL == data || len > W25Q32_PAGE_SIZE) {
        return;
    }

    // 首先等待状态不为忙
    W25Q32_WaitNotBusy();

    // 开启写使能
    W25Q32_WriteEnable();

    SPI_Start();

    // 发送指令
    SPI_SwapByte(0x02);

    // 发送24位地址
    SPI_SwapByte(block);               // A23 ~ A16
    SPI_SwapByte(sector * 16 + page);  // A15 ~ A8
    SPI_SwapByte(0x00);                // A7 ~ A0

    //  依次发送数据
    for (uint16_t i = 0; i < len; i++) {
        SPI_SwapByte(data[i]);
    }

    SPI_Stop();

    W25Q32_WriteDisable();
}

// addr必须 4KB 对齐
void W25Q32_write(uint32_t addr, uint8_t *data, uint32_t len)
{
    // 检查参数是否合法
    if(NULL == data || len == 0 || len > W25Q32_FLASH_SIZE) {
        return;
    }

    // 检查地址是否 4KB 对齐，检查地址是否超过最大地址
    if((addr & 0xfff) != 0 || addr >= W25Q32_FLASH_SIZE || (addr + len > W25Q32_FLASH_SIZE)) {
        return;
    }

    uint16_t pages   = (len + W25Q32_PAGE_SIZE - 1) / W25Q32_PAGE_SIZE;
    for(int i = 0; i < pages; i++) {
        uint32_t start_addr = addr + i * W25Q32_PAGE_SIZE;
        uint8_t block  = (start_addr >> 16) & 0xFF;
        uint8_t sector = (start_addr >> 12) & 0x0F;
        uint8_t page   = (start_addr >> 8) & 0x0F;

        if(page == 0) {
            W25Q32_EraseSector(block, sector);
        }

        int left_bytes = len - i * W25Q32_PAGE_SIZE;

        W25Q32_PageWrite(block, sector, page, data + i * W25Q32_PAGE_SIZE,
            left_bytes > W25Q32_PAGE_SIZE ? W25Q32_PAGE_SIZE : left_bytes);
    }
}

void W25Q32_read(uint32_t addr, uint8_t *buffer, uint32_t len)
{
    // 检查参数是否合法
    if(NULL == buffer || len == 0 || len > W25Q32_FLASH_SIZE) {
        return;
    }

    // 检查地址是否超过最大地址
    if(addr >= W25Q32_FLASH_SIZE || (addr + len > W25Q32_FLASH_SIZE)) {
        return;
    }

    // 首先等待状态不为忙
    W25Q32_WaitNotBusy();

    SPI_Start();

    // 发送指令
    SPI_SwapByte(0x03);

    // 发送24位地址
    SPI_SwapByte(addr >> 16 & 0xff); // A23 ~ A16
    SPI_SwapByte(addr >> 8 & 0xff);  // A15 ~ A8
    SPI_SwapByte(addr >> 0 & 0xff);  // A7 ~ A0

    //  依次读取数据
    for (uint16_t i = 0; i < len; i++)
    {
        buffer[i] = SPI_SwapByte(0xff);
    }

    SPI_Stop();
}

